-- Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
--
-- this file licensed under the Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
--
-- THIS SOFTWARE IS PROVIDED ON AN \"AS IS\" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
-- PURPOSE.
-- See the Mulan PSL v2 for more details.

local log = require 'mc.logging'
local class = require 'mc.class'
local Singleton = require 'mc.singleton'
local props = require 'basic_cooling.define.cooling_properties'
local utils = require 'basic_cooling.cooling_utils'
local enums = require 'basic_cooling.define.cooling_enums'
local cooling_pid_intf = require 'basic_cooling.cooling_pid_intf'
local cooling_requirements = require 'basic_cooling.cooling_requirememts'
local cooling_fans = require 'basic_cooling.cooling_device.cooling_fans'
local abn_pumps = require "basic_cooling.cooling_abnormal_device.abnormal_pump"

local exp_abnormal_fan_pattern = "<(%w+):(%d+):(%d+)>"
local exp_abnormal_requirement_pattern = "<(%w+):0x(%d+)>"

local exp_mgmt = class()

function exp_mgmt:ctor(service, data, fructl_data_keeping)
    self.service = service
    self.data = data
    self.fructl_data_keeping = fructl_data_keeping
    -- 保存异常场景下的风扇转速，key为异常原因(通过gen_exp_speed_key生成)，value为对应风扇ID与转速的table
    self.exp_speed_t = {}
    self.monitorint_status_t = {}
    self.fan_status_t = {}
    self.monitor_temp_t = {}
    self.requirements_instance = cooling_requirements.get_instance()
    self.fans_instance = cooling_fans.get_instance()
    self.abn_pumps_instance = abn_pumps.get_instance()
end

function exp_mgmt:init()
    self.requirements_instance.requirement_info_changed:on(function(action, obj, name, value)
        if action == 'DeleteRequirementExp' then
            -- 温度点删除，需要初始化状态，并尝试删除异常转速
            local req_id = obj[props.REQUIREMENT_ID]
            self.monitorint_status_t[req_id] = nil
            self:delete_requirement_exp_speed(obj)
        end
    end)
    self:register()
end

function exp_mgmt:get_exp_policy_table()
    return self.exp_speed_t
end

-- 根据异常类型、对象id等信息生成唯一的键
function exp_mgmt.gen_exp_speed_key(exp_type, obj_id, fan_abnormal_level)
    if exp_type == enums.exp_type.ABNORMAL_FAN then
        return string.format('<%s:%s:%s>', exp_type, obj_id, fan_abnormal_level)
    elseif exp_type == enums.exp_type.ABNORMAL_REQ or exp_type == enums.exp_type.ALARM_REQ then
        return string.format('<%s:0x%x>', exp_type, obj_id)
    else
        log:error('Unintended exception type')
        return nil
    end
end

function exp_mgmt:add_exp_speed_t(exp_speed_key, abn_policy_table)
    if self.exp_speed_t[exp_speed_key] then
        log:error('Duplicative exp speed, key:%s', exp_speed_key)
        return
    end
    self.exp_speed_t[exp_speed_key] = abn_policy_table
    local abn_policy_info = utils.parse_table_info(abn_policy_table)
    log:notice('Add exception speed, key:(%s), policy(%s)', exp_speed_key, abn_policy_info)
end

function exp_mgmt:delete_exp_speed_t(exp_speed_key)
    if not self.exp_speed_t[exp_speed_key] then
        return
    end

    self.exp_speed_t[exp_speed_key] = nil
    log:notice('Delete exception speed, key:(%s)', exp_speed_key)
end

function exp_mgmt:generate_abn_policy_table(device_table, device_pwms)
    local abn_policy_table = {}
    for key, device_id in pairs(device_table) do
        if type(device_pwms) == "table" then
            abn_policy_table[device_id] = device_pwms[key]
        end

        if type(device_pwms) == "number" then
            abn_policy_table[device_id] = device_pwms
        end
    end
    return abn_policy_table
end

-- 增加温度点异常转速
function exp_mgmt:add_requirement_exp_speed(obj)
    local base_id = obj[props.REQ_BASE_ID] -- 取前8位的bas_id
    local area_id = self.data.requirement_area_map[base_id]
    if not area_id then -- 未配置对应的Area
        log:error("Add requirement abnormal speed failed, Requirement(0x%x) not find CoolingArea(%u)",
            obj[props.REQUIREMENT_ID], base_id)
        return
    end
    local exp_speed_key = self.gen_exp_speed_key(enums.exp_type.ABNORMAL_REQ, obj[props.REQUIREMENT_ID], nil)

    -- 异常调速策略添加风扇调速信息
    local fan_t = self.data.cooling_areas[area_id].FanIdxGroup
    if next(fan_t) then
        local speed = obj.FailedValue
        local exp_table = self:generate_abn_policy_table(fan_t, speed)
        self:add_exp_speed_t(exp_speed_key, exp_table)
    end

    local pump_t = self.data.cooling_areas[area_id].LiquidCoolingDeviceGroup
    if next(pump_t) then
        -- 异常调速策略添加泵调速信息
        local pump_speed = obj.LiquidFailedValue
        local pump_exp_table = self.abn_pumps_instance:generate_abn_policy_table(pump_t, pump_speed)
        self.abn_pumps_instance:add_exp_speed_t(exp_speed_key, pump_exp_table)
    end
end

-- 删除温度点异常转速
function exp_mgmt:delete_requirement_exp_speed(obj)
    local exp_speed_key = self.gen_exp_speed_key(enums.exp_type.ABNORMAL_REQ, obj[props.REQUIREMENT_ID], nil)
    -- 删除风扇异常调速策略
    self:delete_exp_speed_t(exp_speed_key)
    -- 删除泵异常调速策略
    self.abn_pumps_instance:delete_exp_speed_t(exp_speed_key)
end

-- 备用温度点返回其主用温度点,否则返回自身
local function get_actual_requirement(requirements_i, obj)
    if not obj.IsBackupRequirement then
        return obj
    end
    -- 温度点作为备用温度点,通过备用温度点的RequirementId与BackupRequirementIdx是否相同找主温度点
    return requirements_i:get_requirement_by_backup_idx(obj)
end

-- 温度点状态异常调速
-- MonitoringStatus状态异常时，添加异常调速信息到exp_speed_t中
-- MonitoringStatus状态由异常转为正常时，删除温度点状态异常导致的转速
function exp_mgmt:check_requirement_status(req_o)
    local req_id = req_o[props.REQUIREMENT_ID]
    -- FailedValue没有配置不需要进行异常调速直接跳过
    if not req_o.FailedValue or req_o.FailedValue == 0 then
        return
    end
    -- 温度点调速策略不生效时，删除对应温度点的异常调速
    if req_o.IsValid ~= 1 then
        -- 删除调速策略前应当初始化温度点状态表
        self.monitorint_status_t[req_id] = nil
        self:delete_requirement_exp_speed(req_o)
        return
    end

    local m_status = 0
    local temp = req_o[props.MONITORING_VALUE]
    if self.requirements_instance:is_monitoring_abnormal(req_o) then -- 温度点状态不正常
        m_status = 1
    end
    log:debug('Requirement exp check: old status:%u, new status:%u',
        self.monitorint_status_t[req_id] and self.monitorint_status_t[req_id] or 0xff, m_status)
    -- 温度状态由正常变为异常
    if (not self.monitorint_status_t[req_id] or self.monitorint_status_t[req_id] == 0) and m_status == 1 then
        self.monitorint_status_t[req_id] = m_status
        self:add_requirement_exp_speed(req_o)
        utils.thermal_log('%s(id %s) status changes to abnormal, sensor name:%s, status:%s',
            req_o.ObjectName, req_id, req_o.SensorName, req_o.MonitoringStatus)
    -- 温度状态由异常变为正常
    elseif self.monitorint_status_t[req_id] == 1 and m_status == 0 then
        self.monitorint_status_t[req_id] = m_status
        self:delete_requirement_exp_speed(req_o)
        utils.thermal_log('%s(id %s) status changes to normal, sensor name:%s, status:%s',
            req_o.ObjectName, req_id, req_o.SensorName, req_o.MonitoringStatus)
    end
    -- 温度由0变为非0
    if (not self.monitor_temp_t[req_id]) and temp == 0 then
        self.monitor_temp_t[req_id] = true
        utils.thermal_log('%s(id %s) temperature changes to abnormal, sensor name:%s, temperature:%s',
            req_o.ObjectName, req_id, req_o.SensorName, req_o.MonitoringValue)    
    -- 温度由非0变为0
    elseif self.monitor_temp_t[req_id] and temp ~= 0 then
        self.monitor_temp_t[req_id] = nil
        utils.thermal_log('%s(id %s) temperature changes to normal, sensor name:%s, temperature:%s',
            req_o.ObjectName, req_id, req_o.SensorName, req_o.MonitoringValue)
    end
end

-- 温度点状态变化触发回调
function exp_mgmt:policy_add_or_delete_error_speed(obj)
    -- 如果是备用温度点，增加备用温度点的异常调速
    if obj.IsBackupRequirement then
        self:check_requirement_status(obj)
    end
    -- 增加主用或独立温度点的异常调速
    local actual_req = get_actual_requirement(self.requirements_instance, obj)
    -- 如果是备用温度点 存在找不到主用温度点的情况（共风扇板机型）
    if not actual_req then
        return
    end
    self:check_requirement_status(actual_req)
end

local function get_fan_status(cooling_fan_o)
    log:debug("Fan(id:%u) scan: presence(front:%u rear:%u) status(front:%u rear:%u)", cooling_fan_o[props.FAN_ID],
        cooling_fan_o[props.FAN_FRONT_PRESENCE], cooling_fan_o[props.FAN_REAR_PRESENCE],
        cooling_fan_o[props.FRONT_STATUS], cooling_fan_o[props.REAR_STATUS])

    -- 风扇不在位影响大于转速异常，优先检查风扇不在位异常
    if cooling_fan_o[props.FAN_FRONT_PRESENCE] ~= 1 then
        utils.get_instance():frequency_limit_log(enums.log_level.ERROR, 60,
            "Fan(id:%u) is not in position(front:%u)", cooling_fan_o[props.FAN_ID],
            cooling_fan_o[props.FAN_FRONT_PRESENCE])
        return enums.fan_abnormal_level.NOT_IN_PRESENT_FRONT
    end
    if cooling_fan_o[props.FAN_REAR_PRESENCE] ~= 1 then
        utils.get_instance():frequency_limit_log(enums.log_level.ERROR, 60,
            "Fan(id:%u) is not in position(rear:%u)", cooling_fan_o[props.FAN_ID],
            cooling_fan_o[props.FAN_REAR_PRESENCE])
        return enums.fan_abnormal_level.NOT_IN_PRESENT_REAR
    end

    if cooling_fan_o[props.FRONT_STATUS] ~= 0 then
        utils.get_instance():frequency_limit_log(enums.log_level.ERROR, 60,
            "Fan(id:%u) is in an abnormal state(front:%u)", cooling_fan_o[props.FAN_ID],
            cooling_fan_o[props.FRONT_STATUS])
        return enums.fan_abnormal_level.ABNORMAL_ROTATION_FRONT
    end
    if cooling_fan_o[props.REAR_STATUS] ~= 0 then
        utils.get_instance():frequency_limit_log(enums.log_level.ERROR, 60,
            "Fan(id:%u) is in an abnormal state(rear:%u)", cooling_fan_o[props.FAN_ID],
            cooling_fan_o[props.REAR_STATUS])
        return enums.fan_abnormal_level.ABNORMAL_ROTATION_REAR
    end

    return enums.fan_abnormal_level.NORMAL
end

local function is_abnormal_fan_policy_valid(cur_status, valid_status)
    return enums.fan_abnormal_status_mapping[cur_status] and
        enums.fan_abnormal_status_mapping[cur_status] == valid_status
end

function exp_mgmt:abnormal_fan_update_exp_speed_t(exp_type, obj_id, fan_abnormal_l, abn_fan_o)
    local fan_t = abn_fan_o[props.FAN_GROUP]
    local speed = abn_fan_o[props.SPEED_PERCENTAGE]
    local valid_status = abn_fan_o[props.VALID_STATUS]

    -- 恢复正常，将同obj_id下同类型异常转速信息删除
    if fan_abnormal_l == enums.fan_abnormal_level.NORMAL then
        for _, level in pairs(enums.fan_abnormal_level) do
            local key = self.gen_exp_speed_key(exp_type, obj_id, level)
            self:delete_exp_speed_t(key)
        end
        return
    end

    -- 当前异常有效才添加异常转速信息
    if not is_abnormal_fan_policy_valid(fan_abnormal_l, valid_status) then
        return
    end

    -- 将同异常类型和同obj_id的异常转速信息删除
    for _, level in pairs(enums.fan_abnormal_level) do
        if level == enums.fan_abnormal_level.NORMAL then
            goto continue
        end
        local key = self.gen_exp_speed_key(exp_type, obj_id, level)
        self:delete_exp_speed_t(key)

        ::continue::
    end

    -- 加入新的异常转速信息
    local exp_speed_key = self.gen_exp_speed_key(exp_type, obj_id, fan_abnormal_l)
    fan_t = self:generate_abn_policy_table(fan_t, speed)
    self:add_exp_speed_t(exp_speed_key, fan_t)
end

function exp_mgmt:abnormal_fan_scan(objs)
    local abnormal_fans = objs.abnormal_fans
    -- 防抖次数5
    local anti_shake_times <const> = 5
    local fan_err_speed = {}
    local is_fan_scanned = {}
    for _, abn_fan_o in pairs(abnormal_fans) do
        local cooling_fan_o = self.fans_instance.objs[abn_fan_o.FanIdx]
        -- 没找到风扇对象
        if not cooling_fan_o then
            log:debug("[Cooling] The fan(idx:%u) dose not exit", abn_fan_o.FanIdx)
            goto continue
        end

        -- 索引为1代表当前状态，索引为2代表当前状态持续次数
        local fan_status = self.fan_status_t[cooling_fan_o[props.FAN_ID]] and
            self.fan_status_t[cooling_fan_o[props.FAN_ID]] or { [1] = 0,[2] = 0 }

        -- 同一个id的风扇， 每个循环只更新一次状态计数
        if not is_fan_scanned[abn_fan_o.FanIdx] then
            local tmp_status = get_fan_status(cooling_fan_o)
            if tmp_status == fan_status[1] and fan_status[2] < anti_shake_times then
                fan_status[2] = fan_status[2] + 1
                is_fan_scanned[abn_fan_o.FanIdx] = true
            elseif tmp_status ~= fan_status[1] then
                fan_status[1] = tmp_status
                fan_status[2] = 1
                is_fan_scanned[abn_fan_o.FanIdx] = true
            end
        end

        if fan_status[2] >= anti_shake_times and is_fan_scanned[abn_fan_o.FanIdx] then
            self:abnormal_fan_update_exp_speed_t(enums.exp_type.ABNORMAL_FAN, abn_fan_o.FanIdx, fan_status[1],
                abn_fan_o)
        end

        self.fan_status_t[cooling_fan_o[props.FAN_ID]] = fan_status
        log:debug("[Cooling] Abnormal fan scan, id: %u, result: %s", cooling_fan_o[props.FAN_ID],
            table.concat(fan_status, ' ', 1))
        ::continue::
    end

    return fan_err_speed
end

local function cooling_update_area_alarm_speed(c_area, c_requirement, fan_alarm, power_state)
    -- 3个告警温度值
    if #c_requirement.ThresholdValue ~= 3 then
        return
    end

    if power_state ~= enums.power_status.ON and not c_requirement[props.ACTIVE_IN_STANDBY] then
        return
    end

    local alarm_speed = nil
    if c_requirement.MonitoringValue < c_requirement.ThresholdValue[enums.alarm.NORMAL_SPEED_INDEX] then
        alarm_speed = c_requirement.AlarmSpeed[enums.alarm.NORMAL_SPEED_INDEX]
    elseif c_requirement.MonitoringValue < c_requirement.ThresholdValue[enums.alarm.MINOR_SPEED_INDEX] then
        alarm_speed = c_requirement.AlarmSpeed[enums.alarm.MINOR_SPEED_INDEX]
    elseif c_requirement.MonitoringValue < c_requirement.ThresholdValue[enums.alarm.MAJOR_SPEED_INDEX] then
        alarm_speed = c_requirement.AlarmSpeed[enums.alarm.MAJOR_SPEED_INDEX]
    else
        alarm_speed = c_requirement.AlarmSpeed[enums.alarm.CRITICAL_SPEED_INDEX]
    end

    -- 当前告警转速设置给所有风扇
    for _, fan_idx in pairs(c_area.FanIdxGroup) do
        local fan_pos = (fan_idx << 8) | fan_idx
        if fan_alarm[fan_pos] == nil or alarm_speed > fan_alarm[fan_pos] then
            fan_alarm[fan_pos] = alarm_speed
        end
    end
end

-- 温度告警扫描
local function requirement_alarm_scan(self, objs, power_state, requirements_instance)
    local fan_alarm = {} -- 遍历温度点前需格式化fan_alarm
    for _, c_requirement in pairs(requirements_instance:get_objs()) do
        local req_base_id = c_requirement[props.REQ_BASE_ID] -- 取前8位的base_id
        local area_id = objs.requirement_area_map[req_base_id]
        if not area_id then -- 没找到对应的Area
            log:debug("Requirement(0x%x) not find CoolingArea(%u)", c_requirement[props.REQUIREMENT_ID], req_base_id)
            goto continue
        end
        -- 完整的目标调速策略进入时先维护异常调速表
        self:policy_add_or_delete_error_speed(c_requirement)
        if c_requirement.IsValid ~= 1 then -- 温度点不生效
            goto continue
        end
        -- 温度点状态，0:正常,1:错误，状态异常时不下发温度
        if requirements_instance:is_monitoring_abnormal(c_requirement) then
            goto continue
        end
        -- 进风口温度异常则使用转接板温度下发
        cooling_pid_intf.cooling_send_temp_to_pid(self.service,
            c_requirement, requirements_instance:get_temperature_value(c_requirement))
        local c_area = objs.cooling_areas[area_id]
        if not c_area then
            goto continue
        end
        -- 告警调速
        cooling_update_area_alarm_speed(c_area, c_requirement, fan_alarm, power_state)
        ::continue::
    end
    -- 遍历完所有温度点后下发对应的告警转速给PID
    cooling_pid_intf.cooling_tell_almspd_to_pid(self.service, fan_alarm)
end

function exp_mgmt:exception_scan(objs)
    requirement_alarm_scan(self, objs, self.fructl_data_keeping.power_state, self.requirements_instance)
    self:abnormal_fan_scan(objs)
end

local function set_abnormal_fan_info(abnormal_fan_info, temp_requirementId, temp_level, value)
    -- 若不存在最大值信息或者当前获取到的PWM大于已存储的PWM，则直接更新信息
    if not abnormal_fan_info['max_fan_pwm'] or value > abnormal_fan_info['max_fan_pwm'] then
        abnormal_fan_info['max_fan_pwm'] = value
        abnormal_fan_info['requirementId'] = temp_requirementId
        abnormal_fan_info['level'] = temp_level
        return
    end
    -- 若当前获取到PWM等于已存储的PWM，则对requirementId进行判断（此处的requirementId为FanId）
    -- 保存较小的requirementId的信息，如果requirementId相同，则保存优先级最大的异常因子
    if value == abnormal_fan_info['max_fan_pwm'] then
        if abnormal_fan_info['requirementId'] > temp_requirementId then
            abnormal_fan_info['requirementId'] = temp_requirementId
            abnormal_fan_info['level'] = temp_level
            return
        end
        if abnormal_fan_info['requirementId'] == temp_requirementId then
            abnormal_fan_info['level'] = abnormal_fan_info['level'] < temp_level and
                abnormal_fan_info['level'] or temp_level
            return
        end
    end
end

local function set_abnormal_req_info(abnormal_req_info, temp_requirementId, value)
    -- requirementId为16进制数，在此需要先将其转为10进制数
    temp_requirementId = tonumber(tostring(temp_requirementId), 16)
    if not abnormal_req_info['max_fan_pwm'] or value > abnormal_req_info['max_fan_pwm'] then
        abnormal_req_info['max_fan_pwm'] = value
        abnormal_req_info['requirementId'] = temp_requirementId
        return
    end
    if value == abnormal_req_info['max_fan_pwm'] then
        abnormal_req_info['requirementId'] = abnormal_req_info['requirementId'] < temp_requirementId and
            abnormal_req_info['requirementId'] or temp_requirementId
        return
    end
end

local function get_compare_fan_and_req_exception_info(exception_info, abnormal_fan_info, abnormal_req_info,
        is_fan_info_valid, is_req_info_valid)
    -- is_fan_info_valid   is_req_info_valid
    -- false               false              获取到的fan和req均为异常数据
    -- true                false              获取到的fan为有效数据，req为异常数据，直接返回fan对应信息
    -- false               true               获取到的fan为异常数据，req为有效数据，直接返回req对应信息
    -- true                true               获取到的fan和req均为有效数据，则根据转速最大值和优先级(fan > req)返回对应信息
    if not is_fan_info_valid and not is_req_info_valid then
        log:error('Both fan and requirement info is not valid')
        return exception_info
    elseif is_fan_info_valid and not is_req_info_valid then
        if not enums.fan_abnormal_status_mapping_for_ipmi[tonumber(abnormal_fan_info['level'])] then
            log:error('Abnormal fan info level[%s] does not exist', abnormal_fan_info['level'])
            return exception_info
        end
        exception_info.exp_type = enums.max_fan_pwm_type.FAN
        exception_info.max_fan_pwm = abnormal_fan_info['max_fan_pwm']
        exception_info.requirementId = 'Fan'.. abnormal_fan_info['requirementId'] .. ' ' ..
            enums.fan_abnormal_status_mapping_for_ipmi[tonumber(abnormal_fan_info['level'])]
        return exception_info
    elseif not is_fan_info_valid and is_req_info_valid then
        exception_info.exp_type = enums.max_fan_pwm_type.REQUIREMENT
        exception_info.max_fan_pwm = abnormal_req_info['max_fan_pwm']
        exception_info.requirementId = abnormal_req_info['requirementId']
        return exception_info
    else
        if abnormal_fan_info['max_fan_pwm'] >= abnormal_req_info['max_fan_pwm'] then
            if not enums.fan_abnormal_status_mapping_for_ipmi[tonumber(abnormal_fan_info['level'])] then
                log:error('Abnormal fan info level[%s] does not exist', abnormal_fan_info['level'])
                return exception_info
            end
            exception_info.exp_type = enums.max_fan_pwm_type.FAN
            exception_info.max_fan_pwm = abnormal_fan_info['max_fan_pwm']
            exception_info.requirementId = 'Fan'.. abnormal_fan_info['requirementId'] .. ' ' ..
                enums.fan_abnormal_status_mapping_for_ipmi[tonumber(abnormal_fan_info['level'])]
            return exception_info
        else
            exception_info.exp_type = enums.max_fan_pwm_type.REQUIREMENT
            exception_info.max_fan_pwm = abnormal_req_info['max_fan_pwm']
            exception_info.requirementId = abnormal_req_info['requirementId']
            return exception_info
        end
    end
end

function exp_mgmt:get_exception_info()
    local abnormal_fan_info = {
        ['max_fan_pwm'] = nil,
        ['requirementId'] = nil,
        ['level'] = nil
    }
    local abnormal_req_info = {
        ['max_fan_pwm'] = nil,
        ['requirementId'] = nil
    }
    local exception_info = {
        ['exp_type'] = nil,
        ['max_fan_pwm'] = nil,
        ['requirementId'] = nil
    }
    local is_exist_exception_info = false -- 用于校验是否存在exp_speed_t数据
    for key, value in pairs(self.exp_speed_t) do
        is_exist_exception_info = true
        value = utils.get_max_value(value)
        -- 匹配abnormal_fan异常信息
        local exp_type, temp_requirementId, temp_level = string.match(key, exp_abnormal_fan_pattern)
        if exp_type and temp_requirementId and temp_level then
            set_abnormal_fan_info(abnormal_fan_info, temp_requirementId, temp_level, value)
            goto continue
        end
        -- 匹配abnormal_requirement异常信息
        exp_type, temp_requirementId = string.match(key, exp_abnormal_requirement_pattern)
        if exp_type and temp_requirementId then
            set_abnormal_req_info(abnormal_req_info, temp_requirementId, value)
            goto continue
        end
        ::continue::
    end
    if not is_exist_exception_info then
        exception_info.exp_type, exception_info.max_fan_pwm, exception_info.requirementId = 0, 0, 0
        return exception_info -- 返回0,0,0表示不存在风扇异常和传感器异常信息
    end
    local is_fan_info_valid, is_req_info_valid = true, true
    -- 判断获取到的异常信息是fan还是req
    if is_exist_exception_info and
        (not abnormal_fan_info['max_fan_pwm'] or not abnormal_fan_info['requirementId'] or
            not abnormal_fan_info['level']) then
        is_fan_info_valid = false
        log:error('Abnormal fan info does not exist')
    end
    if is_exist_exception_info and (not abnormal_req_info['max_fan_pwm'] or not abnormal_req_info['requirementId']) then
        is_req_info_valid = false
        log:error('Abnormal requirement info does not exist')
    end
    get_compare_fan_and_req_exception_info(exception_info, abnormal_fan_info, abnormal_req_info,
        is_fan_info_valid, is_req_info_valid)
    return exception_info
end

function exp_mgmt:get_abnormal_policy_effective_status(ctx, policy_type)
    local pump_table = self.abn_pumps_instance:get_exp_policy_table()
    local pump_exp_flag, fan_exp_flag, requirement_exp_flag = false, false, false

    if next(pump_table) then
        pump_exp_flag = true
    end

    for key, value in pairs(self.exp_speed_t) do
        value = utils.get_max_value(value)
        -- 匹配abnormal_fan异常信息
        local exp_type, temp_requirementId, temp_level = string.match(key, exp_abnormal_fan_pattern)
        if exp_type and temp_requirementId and temp_level then
            fan_exp_flag = true
            goto continue
        end
        -- 匹配abnormal_requirement异常信息
        exp_type, temp_requirementId = string.match(key, exp_abnormal_requirement_pattern)
        if exp_type and temp_requirementId then
            requirement_exp_flag = true
            goto continue
        end
        ::continue::
    end

    if policy_type == 'Pump' then
        return pump_exp_flag
    end

    if policy_type == 'Fan' then
        return fan_exp_flag
    end

    if policy_type == 'Temperature' then
        return requirement_exp_flag
    end

    if policy_type == 'All' then
        if pump_exp_flag or fan_exp_flag or requirement_exp_flag then
            return true
        end
    end

    return false
end

function exp_mgmt:register()
    self.service:ImplCoolingConfigCoolingConfigGetAbnormalPolicyEffectiveStatus(function(obj, ctx, ...)
        return self:get_abnormal_policy_effective_status(ctx, ...)
    end)
end

return Singleton(exp_mgmt)
